<!--
 * @Description: 大量数据下拉
 * @Author: wind-lc
 * @version: 1.0
 * @Date: 2021-09-02 15:06:29
 * @LastEditTime: 2023-03-21 10:14:42
 * @FilePath: \cscec-pms-admin\src\components\LargeSelect\index.vue
-->
<template>
  <a-select
    v-model="selectValue"
    v-bind="$attrs"
    show-search
    option-filter-prop="children"
    :loading="loading"
    @search="handleSearch"
    @popupScroll="handlepopupScroll($event)"
    @select="handleSelect"
    @blur="handleBlur"
  >
    <a-select-option
      v-for="item in renderList"
      :key="item[replaceFields.key]"
    >
      {{ item[replaceFields.title] }}
    </a-select-option>
  </a-select>
</template>
<script>
export default {
  name: 'LargeSelect',
  props: {
    // 替换字段
    replaceFields: {
      type: Object,
      default: () => {
        return {
          key: 'userId',
          title: 'name'
        }
      }
    },
    // 默认显示条数
    num: {
      type: Number,
      default: 30
    },
    // 选中值(多选Array,单选String)
    value: {
      type: [Array, String, Object],
      require: true
    },
    // 数据加载
    loadDate: {
      type: Function,
      default: null
    }
  },
  components: {},
  data() {
    return {
      // 源数据
      list: [],
      // 渲染列表
      renderList: [],
      // 搜索过滤列表
      filterList: [],
      // 搜索值
      searchValue: '',
      // 选中值
      selectValue: null,
      // 数据加载
      loading: true
    }
  },
  watch: {
    // 默认显示30条
    list: {
      handler(val) {
        if (val.length > 0) {
          this.renderList = val.slice(0, this.num)
          this.addList()
        }
      }
    },
    value: {
      handler(val) {
        this.selectValue = val
      }
    }
  },
  mounted() {
    this.loading = true
    this.loadDate()
      .then((res) => {
        this.list = res
      })
      .finally(() => {
        this.loading = false
      })
  },
  methods: {
    /**
     * @description: 搜索
     * @param {string} value
     * @return {void}
     */
    handleSearch(value) {
      this.searchValue = value
      let filterList = []
      if (value) {
        filterList = this.list.filter((item) => item[this.replaceFields.title].indexOf(value) > -1)
      } else {
        filterList = this.list.slice(0, this.num)
      }
      this.filterList = filterList
      this.renderList = filterList.slice(0, this.num)
    },
    /**
     * @description: 滚动回调
     * @param {e} 事件对象
     * @return {void}
     */
    handlepopupScroll(e) {
      const { target } = e
      if (Math.ceil(target.scrollTop + target.offsetHeight) >= target.scrollHeight) {
        if (this.searchValue === '') {
          this.loadList(this.list)
        } else {
          this.loadList(this.filterList)
        }
      }
    },
    /**
     * @description: 加载数据
     * @param {list} 当前列表
     * @return {void}
     */
    loadList(list) {
      // 渲染列表长度
      const renderL = this.renderList.length
      // 当前数据长度
      const listL = list.length
      let addList = []
      if (renderL < listL) {
        addList = list.slice(renderL, renderL + this.num)
        this.renderList = this.renderList.concat(addList)
      }
    },
    /**
     * @description: 选择回调
     * @param {void}
     * @return {void}
     */
    handleSelect() {
      this.$emit('input', this.selectValue)
    },
    /**
     * @description: 失去焦点
     * @param {void}
     * @return {void}
     */
    handleBlur() {
      this.renderList = this.list.slice(0, this.num)
    },
    /**
     * @description: 添加选中项
     * @param {void}
     * @return {void}
     */
    addList() {
      if (this.value.constructor === Array) {
        this.value.forEach((el) => {
          if (!this.renderList.includes(el)) {
            this.renderList.push(this.list[this.list.findIndex((item) => item[this.replaceFields.key] === el)])
          }
        })
      }
      if (this.value.constructor === String) {
        if (this.renderList.findIndex((el) => el[this.replaceFields.key] === this.value) < 0) {
          this.renderList.push(this.list[this.list.findIndex((item) => item[this.replaceFields.key] === this.value)])
        }
      }
    }
  }
}
</script>
<style lang="less" scoped>
</style>

